<?php
namespace sessions;

class AutoLogin
{
	use PersistentProperties;

	protected $db;
	protected $token_index;
	protected $lifetimeDays = 30;
	protected $expiry;
	protected $cookiePath = '/';
	protected $domain = '';
	protected $secure = null;
	protected $httponly = true;


	public function __construct(\PDO $db, $token_index = 0)
	{
		$this->db = $db;
        if ($this->db->getAttribute(\PDO::ATTR_ERRMODE) !== \PDO::ERRMODE_EXCEPTION){
            $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        }
        $this->token_index = ($token_index <= 31) ? $token_index : 31;
        $this->expiry = time() + ($this->lifetimeDays * 60 * 60 * 24);
    }


    /* create a persistent login for the users
    */

    public function persistentLogin()
    {
        //get user ID
    	if ($_SESSION[$this->sess_ukey] = $this->getUserKey()) {
    		$this->getExistingData();
            // generate a random 32-digit hexidecimal token
    		$token = $this->generateToken();
            // store the token and user id to db
    		$this->storeToken($token);
            // store the single use token as a cookiePath in de users browser
    		$this->setCookie($token);
    		$_SESSION[$this->sess_persist] = true;
    		unset($_SESSION[$this->cookie]);
    	}
    }


    /* check if a valid persistent cookie has been presented

    */

    public function checkCredentials()
    {
        // do nothing if the cookie doesnt exits
    	if (isset($_COOKIE[$this->cookie])) {
    		if ($storedToken = $this->parseCookie()) {
                // delete expired tokens before checking the current one
    			$this->clearOld();
                // log in the user if the token hasnt been used
    			if ($this->checkCookieToken($storedToken, false)) {
                    // log in the users
    				$this->cookieLogin($storedToken);
                    // generate and store fresh single use token
    				$newToken = $this->generateToken();
    				$this->storeToken($newToken);
    				$this->setCookie($newToken);
    			} elseif ($this->checkCookieToken($storedToken, true)) {
                    // if the token has already been used, suspect an attack
                    // delete all tokens associated with the user key
                    // and invalidate the current session
    				$this->deleteAll();
    				$_SESSION = [];
    				$params = session_get_cookie_params();
    				setcookie(session_name(), '' , time()-86400, 
                        $params['path'],$params['domain'],
                        $params['secure'],$params['httponly']);
    				session_destroy();
                    //invalidate the autologin cookie
    				setcookie($this->cookie,'',time()-86400,
                        $this->cookiePath,$this->domain,
                        $this->secure,$this->httponly);				
    			}
    		}
    	}
    }

    /* logs out the user from all sessions or just the current one 
    */

    public function logout($all = true)
    {
    	if ($all) {
    		$this->deleteAll();    		
    	} else {
    		$token = $this->parseCookie();
    		$sql = "UPDATE $this->table_autologin SET $this->col_used = 1
    				WHERE $this->col_token = :token";
    		$stmt = $this->db->prepare($sql);
    		$stmt->bindParam(':token', $token);//klopt
    		$stmt->execute();

    	}

    	setcookie($this->cookie, '', time() - 86400 ,$this->cookiePath, 
    		$this->domain, $this->secure, $this->httponly);
    	

    }

    /* retrieve the users id from the users table 
    */

    protected function getUserKey()
    {
    	$sql = "SELECT $this->col_ukey FROM $this->table_users 
    	WHERE $this->col_name = :username";
    	$stmt = $this->db->prepare($sql);
    	$stmt->bindParam(':username',$_SESSION[$this->sess_uname]);//klopt
    	$stmt->execute();
    	return $stmt->fetchColumn();
    }

    /* Retrieve the users data from the most recent session 
    */

    protected function getExistingData()
    {
    	$sql = "SELECT $this->col_data FROM $this->table_autologin
    	WHERE $this->col_ukey = :key
    	ORDER BY $this->col_created DESC";
    	$stmt = $this->db->prepare($sql);
    	$stmt->bindParam(':key',$_SESSION[$this->sess_ukey]);//dit klopt
    	$stmt->execute();
        // get the most recent result
    	if ($data=$stmt->fetchColumn()) {
            // populate the $_SESSION superglobal array
    		session_decode($data);
    	}
        // Release the db connection for other queries
    	$stmt->closeCursor();

    }

    /* generate a random 32 character string for single-use token 
    */

    protected function generateToken()
    {
    	return bin2hex(openssl_random_pseudo_bytes(16));
    }

    /* stores the users ID en single use token in de DB
    */

    protected function storeToken($token)
    {
	    try {
	    	$sql = "INSERT INTO $this->table_autologin
	    	($this->col_ukey, $this->col_token)
	    	VALUES (:key,:token)";
	    	$stmt = $this->db->prepare($sql);
	    	$stmt->bindParam(':key',$_SESSION[$this->sess_ukey]);//ditklopt
	    	$stmt->bindParam(':token', $token);//klopt
	    	$stmt->execute();
	    		
		} catch (\PDOException $e){
			if ($this->db->inTransaction()) {
				$this->db->rollBack();
			} 
			throw $e;
	   }
    }

    /* creates and stores autologin cookie in users browser
    */

    protected function setCookie($token)
    {
    	$merged = str_split($token);
    	array_splice($merged, hexdec($merged[$this->token_index]),0,$_SESSION[$this->sess_ukey]);
    	$merged = implode('',$merged);

    	$token = $_SESSION[$this->sess_uname] . '|' . $merged;
    	setcookie($this->cookie, $token, $this->expiry,
            $this->cookiePath, $this->domain, 
            $this->secure, $this->httponly);

    }

    protected function parseCookie()
    {
        // seperate the username and submitted token
    	$parts = explode('|', $_COOKIE[$this->cookie]);
    	$_SESSION[$this->sess_uname]  = $parts[0];
    	$token = $parts[1];

        //proceed only if the username is valid
    	if ($_SESSION[$this->sess_ukey] = $this->getUserKey()) {
            // remove the users ID from the submitted cookie token
    		return str_replace($_SESSION[$this->sess_ukey], '',$token);
    	} else {
    		return false;
    	}    	
    }

    protected function clearOld()
    {
    	$sql = "DELETE FROM $this->table_autologin
    			WHERE DATE_ADD($this->col_created, INTERVAL :expiry DAY) < NOW()";
    	$stmt = $this->db->prepare($sql);
    	$stmt->bindParam(':expiry',$this->lifetimeDays);//klopt
    	$stmt->execute();
    }

    protected function checkCookieToken($token, $used)
    {
    	$sql = "SELECT COUNT(*) FROM $this->table_autologin 
    			WHERE $this->col_ukey = :key AND $this->col_token = :token
    			AND $this->col_used = :used";
    	$stmt = $this->db->prepare($sql);
    	$stmt->bindParam(':key',$_SESSION[$this->sess_ukey]);//klopt
    	$stmt->bindParam(':token',$token);//klopt
    	$stmt->bindParam(':used',$used, \PDO::PARAM_BOOL);//klopt
    	$stmt->execute();
    	if ($stmt->fetchColumn() > 0) {
    	 	return true;
    	} else {
    		return false;
    	}
    }

    protected function deleteAll()
    {
    	$sql = "DELETE FROM $this->table_autologin WHERE $this->col_ukey = :key";
    	$stmt = $this->db->prepare($sql);
    	$stmt->bindParam(':key',$_SESSION[$this->sess_ukey]);//klopt
    	$stmt->execute();
    }


    protected function cookieLogin($token)
    {
    	try {
    		$this->getExistingData($_SESSION[$this->sess_ukey]);

    		$sql = "UPDATE $this->table_autologin SET $this->col_used = 1
    		WHERE $this->col_ukey = :key AND $this->col_token = :token";
    		$stmt = $this->db->prepare($sql);
    		$stmt->bindParam(':key',$_SESSION[$this->sess_ukey]);//klopt
      		$stmt->bindParam(':token',$token);//klopt
    		$stmt->execute();

    		session_regenerate_id(true);

    		$_SESSION[$this->cookie] = true;
    		unset($_SESSION[$this->sess_auth]);
    		unset($_SESSION[$this->sess_revalid]);
    		unset($_SESSION[$this->sess_persist]);
    	} catch (\PDOException $e){
			if ($this->db->inTransaction()) {
				$this->db->rollBack();
			} 
			throw $e;
		}
    }
}





?>